package com.wish.group05.shoufang.util;

import java.io.InputStream;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.BitSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;

/**
 * 字符串操作相关工具类
 * <p/>
 * User: moxiao.hd Date: 14-4-1 Time: 下午4:41
 */
public class StringUtil {

    public static final Charset UTF_8 = Charset.forName("UTF-8");
    public static final Charset GBK = Charset.forName("GBK");
    private static final Pattern NUM_PARAM = Pattern.compile("\\{\\d+\\}");
    private static final Pattern MAP_PARAM = Pattern.compile("\\{\\w+\\}");
    private static final Pattern REPEAT = Pattern
            .compile("\\{([^}]+)\\[(\\d+)\\.\\.(\\d+)\\]\\}");
    private static final BitSet URLEncodeSafe = new BitSet();

    static {
        for (int i = 'a'; i < 'z'; i++) {
            URLEncodeSafe.set(i);
        }

        for (int i = 'A'; i < 'Z'; i++) {
            URLEncodeSafe.set(i);
        }

        URLEncodeSafe.set('.');
        URLEncodeSafe.set('-');
        URLEncodeSafe.set('*');
        URLEncodeSafe.set('_');
    }

    /**
     * @param object
     * @return
     */
    public static String toString(Object object) {
        return object != null ? object.toString() : null;
    }

    /**
     * 判断str是否是null或""
     *
     * @param str
     * @return
     */
    public static boolean isEmpty(String str) {
        return StringUtils.isEmpty(str);
    }

    /**
     * 判断str是否不是null或""
     *
     * @param str
     * @return
     */
    public static boolean isNotEmpty(String str) {
        return StringUtils.isNotEmpty(str);
    }

    /**
     * trim后判断str是否是null或""
     *
     * @param str
     * @return
     */
    public static boolean isBlank(String str) {
        return StringUtils.isBlank(str);
    }

    /**
     * trim后判断str是否是null或""
     *
     * @param strs
     * @return
     */
    public static boolean isBlank(String... strs) {
        for (String str : strs) {
            if (isBlank(str)) {
                return true;
            }
        }

        return false;
    }

    /**
     * trim后判断str是否不是null或""
     *
     * @param str
     * @return
     */
    public static boolean isNotBlank(String str) {
        return StringUtils.isNotBlank(str);
    }

    /**
     * 判断str是否以prefix开头，大小写敏感
     *
     * @param str
     * @param prefix
     * @return
     */
    public static boolean startsWith(String str, String prefix) {
        return StringUtils.startsWith(str, prefix);
    }

    /**
     * 判断str是否以prefix开头，大小写不敏感
     *
     * @param str
     * @param prefix
     * @return
     */
    public static boolean startsWithIgnoreCase(String str, String prefix) {
        return StringUtils.startsWithIgnoreCase(str, prefix);
    }

    /**
     * 判断str是否以suffix结束，大小写敏感
     *
     * @param str
     * @param suffix
     * @return
     */
    public static boolean endsWith(String str, String suffix) {
        return StringUtils.endsWith(str, suffix);
    }

    /**
     * 判断str是否以suffix结束，大小写不敏感
     *
     * @param str
     * @param suffix
     * @return
     */
    public static boolean endsWithIgnoreCase(String str, String suffix) {
        return StringUtils.endsWithIgnoreCase(str, suffix);
    }

    /**
     * 把array中元素使用delimiter分隔拼接为一个字符串
     *
     * @param array
     * @param delimiter
     * @return
     */
    public static String join(Object[] array, char delimiter) {
        return StringUtils.join(array, delimiter);
    }

    /**
     * 把array中元素使用delimiter分隔拼接为一个字符串
     *
     * @param array
     * @param delimiter
     * @return
     */
    public static String join(Object[] array, String delimiter) {
        return StringUtils.join(array, delimiter);
    }

    /**
     * 把str按照delimiter字符切分为数个token，空串token会被丢弃
     *
     * @param str
     * @param delimiter
     * @return
     */
    public static String[] split(String str, char delimiter) {
        return StringUtils.split(str, delimiter);
    }

    /**
     * 把str按照delimiter字符串（非正则）切分为数个token，空串token会被丢弃
     *
     * @param str
     * @param delimiter
     * @return
     */
    public static String[] split(String str, String delimiter) {
        return StringUtils.split(str, delimiter);
    }

    /**
     * 把str全部转化为小写
     *
     * @param str
     * @return
     */
    public static String toLowerCase(String str) {
        if (str == null) {
            return null;
        }

        return str.toLowerCase();
    }

    /**
     * 把str全部转化为大写
     *
     * @param str
     * @return
     */
    public static String toUpperCase(String str) {
        if (str == null) {
            return null;
        }

        return str.toUpperCase();
    }

    /**
     * 判断str是否包含target字符
     *
     * @param str
     * @param target
     * @return
     */
    public static boolean contains(String str, char target) {
        return isNotEmpty(str) && str.indexOf(target) != -1;
    }

    /**
     * 判断str是否包含target字符串
     *
     * @param str
     * @param target
     * @return
     */
    public static boolean contains(String str, String target) {
        return isNotEmpty(str) && str.contains(target);
    }

    /**
     * 把target字符从str中删除
     *
     * @param str
     * @param target
     * @return
     */
    public static String remove(String str, char target) {
        return StringUtils.remove(str, target);
    }

    /**
     * 把target字符串从str中删除
     *
     * @param str
     * @param target
     * @return
     */
    public static String remove(String str, String target) {
        return StringUtils.remove(str, target);
    }

    /**
     * 把str中的字符按照asc/unicode顺序排列
     *
     * @param str
     * @return
     */
    public static String sortChar(String str) {
        char[] chars = str.toCharArray();
        Arrays.sort(chars);
        return new String(chars);
    }

    /**
     * 将str前后用wrapper包裹
     *
     * @param str
     * @param wrapper
     * @return
     */
    public static String pack(String str, char wrapper) {
        if (str == null) {
            return null;
        }

        return wrapper + str + wrapper;
    }

    /**
     * 将str前后的wrapper包裹去除 如果没有被wrapper包裹，则直接返回str
     *
     * @param str
     * @param wrapper
     * @return
     */
    public static String unpack(String str, char wrapper) {
        if (str == null) {
            return null;
        }

        if (str.length() < 2) {
            return str;
        }

        if (str.charAt(0) == wrapper
                && str.charAt(str.length() - 1) == wrapper) {
            return str.substring(1, str.length() - 1);
        } else {
            return str;
        }
    }

    /**
     * 把parameters参数依次注入template的?中
     *
     * @param template
     *            变量以?代替，可使用\?转义?
     * @param parameters
     *            注入参数
     * @return
     */
    public static String merge(String template, Object... parameters) {
        if (template == null) {
            return null;
        }

        int start = 0;
        int idx = 0;
        int paramIdx = 0;
        StringBuilder sb = new StringBuilder(template.length() << 1);
        while ((idx = template.indexOf('?', start)) >= 0) {
            if (idx != 0 && template.charAt(idx - 1) == '\\') {
                sb.append(template, start, idx - 1);
                sb.append('?');
                start = idx + 1;
            } else {
                if (paramIdx >= parameters.length || paramIdx < 0) {
                    throw new IndexOutOfBoundsException(
                            "parameters index must in [" + 0 + ","
                                    + (parameters.length - 1) + "], actual:"
                                    + paramIdx);
                }

                sb.append(template, start, idx);
                sb.append(parameters[paramIdx++]);
                start = idx + 1;
            }
        }

        if (start < template.length()) {
            sb.append(template.substring(start));
        }

        return sb.toString();
    }

    /**
     * 把parameters参数依次注入template的{idx}中，idx是参数在parameters中的位置，从0开始
     *
     * @param template
     *            变量以{0}，{1}，{2}...代替
     * @param parameters
     *            注入参数，数量应大于模板中最大编号
     * @return
     */
    public static String mergeIdx(String template, Object... parameters) {
        if (template == null) {
            return null;
        }

        Matcher m = NUM_PARAM.matcher(template);
        StringBuilder sb = new StringBuilder(template.length() << 1);
        int start = 0;
        while (m.find(start)) {
            int paramIdx = parseInt(template, m.start(), m.end());
            if (paramIdx >= parameters.length || paramIdx < 0) {
                throw new IndexOutOfBoundsException("parameters index must in ["
                        + 0 + "," + (parameters.length - 1) + "], actual:"
                        + paramIdx);
            }

            sb.append(template, start, m.start());
            sb.append(parameters[paramIdx]);
            start = m.end();
        }

        if (start < template.length()) {
            sb.append(template.substring(start));
        }

        return sb.toString();
    }

    /**
     * 把parameters参数依次注入template的{key}中，key是paramMap的key
     *
     * @param template
     *            变量以{key1}，{key2}，{key3}...代替
     * @param paramMap
     *            注入参数map
     * @return
     */
    public static String merge(String template, Map<String, Object> paramMap) {
        if (template == null) {
            return null;
        }

        Matcher m = MAP_PARAM.matcher(template);
        StringBuilder sb = new StringBuilder(template.length() << 1);
        int start = 0;
        while (m.find(start)) {
            String key = m.group().substring(1, m.group().length() - 1);
            if (!paramMap.containsKey(key)) {
                throw new NullPointerException(
                        "paramMap does't contain key:" + key);
            }

            sb.append(template, start, m.start());
            sb.append(paramMap.get(key));
            start = m.end();
        }

        if (start < template.length()) {
            sb.append(template.substring(start));
        }

        return sb.toString();
    }

    /**
     * @param template
     * @param startIdx
     * @param endIdx
     * @return
     */
    private static int parseInt(String template, int startIdx, int endIdx) {
        String numStr = template.substring(startIdx + 1, endIdx - 1);
        return Integer.parseInt(numStr);
    }

    /**
     * @param str
     *            {aaa[0..1]}
     * @return
     */
    public static String repeat(String str) {
        Matcher m = REPEAT.matcher(str);
        StringBuilder sb = new StringBuilder();
        int idx = 0;
        while (m.find()) {
            sb.append(str, idx, m.start());
            String repeat = m.group(1);
            int start = Integer.parseInt(m.group(2));
            int end = Integer.parseInt(m.group(3));

            for (int i = start; i <= end; i++) {
                sb.append(repeat).append(i).append(",");
            }
            sb.delete(sb.length() - 1, sb.length());
            idx = m.end();
        }

        if (idx < str.length()) {
            sb.append(str.substring(idx));
        }
        return sb.toString();
    }

    /**
     * 计算InputStream的md5值
     *
     * @param in
     * @return
     */
    public static String md5sum(InputStream in) {
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");

            int c;
            in.mark(0);
            while ((c = in.read()) != -1) {
                md5.update((byte) c);
            }
            in.close();

            byte[] md5Bytes = md5.digest();
            final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();
            StringBuilder ret = new StringBuilder(md5Bytes.length * 2);
            for (int i = 0; i < md5Bytes.length; i++) {
                ret.append(HEX_DIGITS[(md5Bytes[i] >> 4) & 0x0f]);
                ret.append(HEX_DIGITS[md5Bytes[i] & 0x0f]);
            }

            return ret.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * trim输入字符串
     *
     * @param value
     * @return
     */
    public static String trim(String value) {
        if (StringUtil.isBlank(value)) {
            return null;
        } else {
            return value.trim();
        }
    }

    /**
     * map转换成string，格式是k1:v1,k2:v2
     *
     * @param map
     * @return
     */
    public static <T, S> String mapToStr(Map<T, S> map) {
        return mapToStr(map, 16);
    }

    public static <T, S> String mapToStr(Map<T, S> map, int capacity) {
        return mapToStr(map, 16, ",");
    }

    public static <T, S> String mapToStr(Map<T, S> map, int capacity,
                                         String delimiter) {
        if (map == null) {
            return "";
        }
        StringBuilder sb = new StringBuilder(capacity);
        for (Map.Entry<T, S> entry : map.entrySet()) {
            sb.append(entry.getKey());
            sb.append(":");
            sb.append(entry.getValue());
            sb.append(delimiter);
        }
        if (sb.length() > 0) {
            return sb.substring(0, sb.length() - 1);
        } else {
            return "";
        }
    }

    /**
     * set转换成string，格式是s1,s2,s3
     *
     * @param set
     * @return
     */
    public static <T> String setToStr(Set<T> set) {
        return setToStr(set, 16);
    }

    public static <T> String setToStr(Set<T> set, int capacity) {
        if (set == null) {
            return "";
        }
        StringBuilder sb = new StringBuilder(capacity);
        for (T t : set) {
            sb.append(t);
            sb.append(",");
        }
        if (sb.length() > 0) {
            return sb.substring(0, sb.length() - 1);
        } else {
            return "";
        }

    }

    /**
     * list转换成string，格式是l1,l2,l3
     *
     * @param list
     * @return
     */
    public static <T> String listToStr(List<T> list) {
        return listToStr(list, 16);
    }

    public static <T> String listToStr(List<T> list, int capacity) {
        if (list == null) {
            return "";
        }
        StringBuilder sb = new StringBuilder(capacity);
        for (T t : list) {
            sb.append(t);
            sb.append(",");
        }
        if (sb.length() > 0) {
            return sb.substring(0, sb.length() - 1);
        } else {
            return "";
        }

    }

    /**
     * 把byte转化成utf-8字符串
     *
     * @param bytes
     * @return
     */
    public static String utf8String(byte[] bytes) {
        return new String(bytes, UTF_8);
    }

    /**
     * 把byte转化成GBK字符串
     *
     * @param bytes
     * @return
     */
    public static String gbkString(byte[] bytes) {
        return new String(bytes, GBK);
    }

    /**
     * 返回字符串的utf-8编码
     *
     * @param str
     * @return
     */
    public static byte[] utf8Bytes(String str) {
        return str.getBytes(UTF_8);
    }

    /**
     * 返回字符串的GBK编码
     *
     * @param str
     * @return
     */
    public static byte[] gbkBytes(String str) {
        return str.getBytes(GBK);
    }

    /**
     * url gbk解码
     *
     * @param str
     * @return
     */
    public static String gbkUrlDecode(String str) {
        try {
            return URLDecoder.decode(str, "GBK");
        } catch (Exception e) {
            return str;
        }
    }

    /**
     * Returns a string representation of the given array. This method takes an
     * Object to allow also all types of primitive type arrays.
     *
     * @param array
     *            The array to create a string representation for.
     * @return The string representation of the array.
     * @throws IllegalArgumentException
     *             If the given object is no array.
     */
    public static String arrayToString(Object array) {
        if (array == null) {
            return "null";
        }

        if (array instanceof int[]) {
            return Arrays.toString((int[]) array);
        }
        if (array instanceof long[]) {
            return Arrays.toString((long[]) array);
        }
        if (array instanceof Object[]) {
            return Arrays.toString((Object[]) array);
        }
        if (array instanceof byte[]) {
            return Arrays.toString((byte[]) array);
        }
        if (array instanceof double[]) {
            return Arrays.toString((double[]) array);
        }
        if (array instanceof float[]) {
            return Arrays.toString((float[]) array);
        }
        if (array instanceof boolean[]) {
            return Arrays.toString((boolean[]) array);
        }
        if (array instanceof char[]) {
            return Arrays.toString((char[]) array);
        }
        if (array instanceof short[]) {
            return Arrays.toString((short[]) array);
        }

        if (array.getClass().isArray()) {
            return "<unknown array type>";
        } else {
            throw new IllegalArgumentException(
                    "The given argument is no array.");
        }
    }

    /**
     * 字符转unicode
     *
     * @param str
     * @return
     */
    public static String char2unicode(String str) {
        int index = 0;
        int begin = 0;
        int end = str.length();
        StringBuffer sb = new StringBuffer();
        while (index != -1) {
            index = str.indexOf("\\u", begin);
            if (index > begin) {
                sb.append(str, begin, index);
            }
            if (index == -1) {
                sb.append(str.substring(begin));
                break;
            } else if (index + 6 <= end) {
                int a = Character.digit(str.charAt(index + 2), 16);
                int b = Character.digit(str.charAt(index + 3), 16);
                int c = Character.digit(str.charAt(index + 4), 16);
                int d = Character.digit(str.charAt(index + 5), 16);

                if (a != -1 && b != -1 && c != -1 && d != -1) {
                    sb.append((char) (a << 12 | b << 8 | c << 4 | d));
                    begin = index + 6;
                } else {
                    sb.append("\\u");
                    begin = index + 2;
                }
            } else {
                sb.append("\\u");
                begin = index + 2;
            }
        }

        return sb.toString();
    }

    /**
     * 获取连接参数
     *
     * @param key
     * @return
     */
    public static String getUrlParam(String url, String key) {
        if (url == null || key == null) {
            return null;
        }

        int paramIdx = url.indexOf("?");
        if (paramIdx != -1) {
            url = url.substring(paramIdx + 1);
        }

        int idx = url.indexOf(key + "=");
        if (idx == -1) {
            return "";
        }

        int startIdx = idx + key.length() + 1;
        int endIdx = url.indexOf("&", startIdx);
        if (endIdx == -1) {
            return url.substring(startIdx);
        } else {
            return url.substring(startIdx, endIdx);
        }
    }

    /**
     * 获取文件后缀，不包含.
     *
     * @param fileName
     * @param defaultValue
     * @return
     */
    public static String getSuffix(String fileName, String defaultValue) {
        if (fileName != null && fileName.contains(".")) {
            return fileName.substring(fileName.lastIndexOf(".") + 1);
        }
        return defaultValue;
    }

}
